package com.cy.apt_processor;

import com.cy.apt_annotation.BindView;
import com.google.auto.service.AutoService;
import com.squareup.javapoet.JavaFile;

import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.Elements;
import javax.tools.Diagnostic;

/**
 * 日志
 注: 注解init
 注: 注解getSupportedSourceVersion
 注: 注解getSupportedAnnotationTypes
 注: 注解getSupportedOptions
 注: 注解getSupportedAnnotationTypes
 注: 注解process begin
 注: 注解process set [com.cy.apt_annotation.BindView]
 //第一次回调处理当前module中所有的类，不管里面是否有注解，set返回支持的注解
 注: 注解process roundEnvironment [errorRaised=false, rootElements=[com.cy.apttest.ThirdActivity, com.cy.apttest.SecActivity, com.cy.apttest.MainActivity, com.cy.apttest.BuildConfig], processingOver=false]
 注: 注解process end
 注: 注解getSupportedOptions
 注: 注解getSupportedAnnotationTypes
 注: 注解process begin
 注: 注解process set []
 //第二次处理生成的所有的类
 注: 注解process roundEnvironment [errorRaised=false, rootElements=[com.cy.apttest.MainActivity_ViewBinding, com.cy.apttest.SecActivity_ViewBinding], processingOver=false]
 注: 注解process end
 注: 注解getSupportedAnnotationTypes
 注: 注解process begin
 注: 注解process set []
 //第三次通知处理结束
 注: 注解process roundEnvironment [errorRaised=false, rootElements=[], processingOver=true]
 注: 注解process end
 */
@AutoService(Processor.class)
public class BindViewProcessor extends AbstractProcessor {
    private static final String MODULE_NAME_KEY = "module_name";
    private static final String MODULE_MAIN_KEY = "module_main";
    private static final String MODULES_LIST = "modules_list";
    private static final String MODULE_MAIN_VALUE = "yes";

    //用于打印日志
    private Messager mMessager;
    //用于处理元素
    private Elements mElementUtils;
    //用来创建java文件或者class文件
    private Filer mFiler;
    /**
     * 获取gradle中配置的参数，比如module的名称，可以通过annotationProcessorOptions传进来
     * android {
     *     defaultConfig {
     *         javaCompileOptions {
     *             annotationProcessorOptions {
     *                 arguments = [module_name: project.getName(), module_main: "yes", modules_list: "app&module1&module2"]
     *             }
     *         }
     *     }
     * }
     */
    private Map<String, String> mOptions;
    private Map<String, ClassCreatorProxy> mProxyMap = new HashMap<>();

    /**
     * 父类在init的时候已经赋值了这个变量，但是不是m开头，不符合代码规范
     * protected ProcessingEnvironment processingEnv;
     */
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        mMessager = processingEnv.getMessager();
        mElementUtils = processingEnv.getElementUtils();
        mFiler = processingEnv.getFiler();
        mOptions = processingEnv.getOptions();
        mMessager.printMessage(Diagnostic.Kind.NOTE, "注解init ");
    }

    /**
     * 返回支持的注解类型
     */
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        mMessager.printMessage(Diagnostic.Kind.NOTE, "注解getSupportedAnnotationTypes ");
        HashSet<String> supportTypes = new LinkedHashSet<>();
        supportTypes.add(BindView.class.getCanonicalName());
        return supportTypes;
    }

    /**
     * 返回支持的jdk版本
     */
    @Override
    public SourceVersion getSupportedSourceVersion() {
        mMessager.printMessage(Diagnostic.Kind.NOTE, "注解getSupportedSourceVersion");
        return SourceVersion.latestSupported();
    }

    /**
     * 设置annotationProcessorOptions中的map支持的key
     */
    @Override
    public Set<String> getSupportedOptions() {
        mMessager.printMessage(Diagnostic.Kind.NOTE, "注解getSupportedOptions");
        Set<String> set = new HashSet<>();
        set.add(MODULE_NAME_KEY);
        set.add(MODULE_MAIN_KEY);
        set.add(MODULES_LIST);
        return set;
    }

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        mMessager.printMessage(Diagnostic.Kind.NOTE, "注解process begin");
        mMessager.printMessage(Diagnostic.Kind.NOTE, "注解process set "+set);
        mMessager.printMessage(Diagnostic.Kind.NOTE, "注解process roundEnvironment "+roundEnvironment);
        mProxyMap.clear();
        //得到所有的注解
        Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(BindView.class);
        for (Element element : elements) {
            VariableElement variableElement = (VariableElement) element;
            TypeElement enclosingElement = (TypeElement) variableElement.getEnclosingElement();
            String fullClassName = enclosingElement.getQualifiedName().toString();
            mMessager.printMessage(Diagnostic.Kind.NOTE, "注解process for qualifiedName "+fullClassName);
            //elements的信息保存到mProxyMap中
            ClassCreatorProxy proxy = mProxyMap.get(fullClassName);
            if (proxy == null) {
                proxy = new ClassCreatorProxy(mElementUtils, enclosingElement);
                mProxyMap.put(fullClassName, proxy);
            }
            BindView bindAnnotation = variableElement.getAnnotation(BindView.class);
            int id = bindAnnotation.value();
            proxy.putElement(id, variableElement);
        }
        //通过遍历mProxyMap，创建java文件
        //通过StringBuilder生成
        /*for (String key : mProxyMap.keySet()) {
            ClassCreatorProxy proxyInfo = mProxyMap.get(key);
            try {
                JavaFileObject jfo = processingEnv.getFiler().createSourceFile(proxyInfo.getProxyClassFullName(), proxyInfo.getTypeElement());
                Writer writer = jfo.openWriter();
                writer.write(proxyInfo.generateJavaCode());
                writer.flush();
                writer.close();
                mMessager.printMessage(Diagnostic.Kind.NOTE, " --> create " + proxyInfo.getProxyClassFullName() + "success");
            } catch (IOException e) {
                mMessager.printMessage(Diagnostic.Kind.NOTE, " --> create " + proxyInfo.getProxyClassFullName() + "error");
            }
        }*/
        //通过javapoet生成
        for (String key : mProxyMap.keySet()) {
            ClassCreatorProxy proxyInfo = mProxyMap.get(key);
            JavaFile javaFile = JavaFile.builder(proxyInfo.getPackageName(),
                    proxyInfo.javapoetGenerate()).build();
            try {
                //　生成文件
//                javaFile.writeTo(processingEnv.getFiler());
                javaFile.writeTo(mFiler);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        mMessager.printMessage(Diagnostic.Kind.NOTE, "注解process end");
        return true;
    }

}
